#include "StdAfx.h"
#include "CudaSource.h"
#include "InternalManager.h"
using namespace System::Windows::Media;
using namespace System::Windows;
using namespace System;

namespace GRIP
{
	namespace Cuda
	{
		InternalCudaSource::InternalCudaSource(int Width, int Height)
		{
			DirectXErrorCheck(InternalManager::CreateSurface((uint)Width, (uint)Height, true, 0, &Direct3DSurface),
				"Unable to create a new DirectX surface.");
			CudaErrorCheck(cudaGraphicsD3D9RegisterResource(&CudaSurfaceBridge, Direct3DSurface, cudaGraphicsRegisterFlagsSurfaceLoadStore));
			CudaErrorCheck(cudaGraphicsMapResources(1, &CudaSurfaceBridge, 0));
			CudaErrorCheck(cudaGraphicsSubResourceGetMappedArray((cudaArray **)&CudaSurfaceArray, CudaSurfaceBridge, 0, 0));
		};

		InternalCudaSource::~InternalCudaSource()
		{
			CudaErrorCheck(cudaGraphicsUnmapResources(1, &CudaSurfaceBridge, 0));
			CudaErrorCheck(cudaGraphicsUnregisterResource(CudaSurfaceBridge));
			Direct3DSurface->Release();
		}


		CudaSource::CudaSource(int Width, int Height)
		{
			this->Width = Width;
			this->Height = Height;
			Bounds = gcnew Int32Rect(0, 0, Width, Height);
			InternalSource = new InternalCudaSource(Width, Height);
			ManagedSourcePtr = (IntPtr)InternalSource->Direct3DSurface;
            Lock();
            SetBackBuffer(D3DResourceType::IDirect3DSurface9, ManagedSourcePtr);
            Unlock();
		};

		void CudaSource::Update()
		{
			if (IsFrontBufferAvailable)
            {
                Lock();
                AddDirtyRect(*Bounds);
                Unlock();
            }
		};

		cudaArray* CudaSource::GetMappedArray()
		{
			return InternalSource->CudaSurfaceArray;
		}

		void* CudaSource::GetMappedArrayCrossAssembly()
		{
			return InternalSource->CudaSurfaceArray;
		}

		void CudaSource::Clear()
		{
			cudaMemset(InternalSource->CudaSurfaceArray, 0, Width * Height);
		}
	}
}
